﻿using FPSO.Models.Constant;
using FPSO.Models.Domain;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Management.Instrumentation;

namespace FPSO.Services.Impl
{
    public class SafeLoadAlgorithmService : IDisposable
    {
        private static SafeLoadAlgorithmService instance = null;

        private NamedPipeClientStream pipeClient = null;
        private StreamWriter pipeWriter = null;
        private StreamReader pipeReader = null;

        private Dictionary<string, string> tankId2NameDic;
        private Dictionary<string, string> tankName2IdDic;

        private SafeLoadAlgorithmService()
        {
            tankId2NameDic = new Dictionary<string, string>();
            tankName2IdDic = new Dictionary<string, string>();

			List<TankConstant.ConstantTankInfo> constantlist = TankConstant.ConstantList;
			foreach (TankConstant.ConstantTankInfo constantlisti in constantlist)
			{
				tankId2NameDic.Add(constantlisti.TankID, constantlisti.TankName);
				tankName2IdDic.Add(constantlisti.TankName, constantlisti.TankID);
			}
        }

        public static SafeLoadAlgorithmService GetInstance()
        {
            if (instance == null)
            {
                instance = new SafeLoadAlgorithmService();
            }

            return instance;
        }

        public Dictionary<string, double> GetFullDicByVolumDic(Dictionary<string, double> tankVolumDic)
        {
            Dictionary<string, double> fullDic = new Dictionary<string, double>();
            foreach(KeyValuePair<string, double> volumPair in tankVolumDic)
            {
                double full = 0;
                double totalVolm = TankConstant.GetTankVolume(volumPair.Key);
                if (volumPair.Value <= 0) { full = 0d; }
                else if (volumPair.Value >= totalVolm) { full = 100d; }
                else { full = (volumPair.Value * 100) / totalVolm; }
                fullDic.Add(volumPair.Key, full);
            }
            return fullDic;
        }

        public Dictionary<string, double> GetLevelDicByVolumDic(Dictionary<string, double> tankVolumDic)
        {
            Dictionary<string, double> fullDic = new Dictionary<string, double>();
            foreach (KeyValuePair<string, double> volumPair in tankVolumDic)
            {
                double full = 0;
                double totalVolm = TankConstant.GetTankVolume(volumPair.Key);
                if (volumPair.Value <= 0) { full = 0d; }
                else if (volumPair.Value >= totalVolm) { full = 100d; }
                else { full = (volumPair.Value * 100) / totalVolm; }
                fullDic.Add(volumPair.Key, full);
            }
            return fullDic;
        }
        public ManualCalcResult CallManualCalc(Dictionary<string, double> tankFullDic, int datatype)
        {
            List<string> argList = new List<string>();
            foreach (KeyValuePair<string, double> tankFull in tankFullDic)
            {
                if (tankId2NameDic.ContainsKey(tankFull.Key))
                {
                    argList.Add(tankId2NameDic[tankFull.Key]);
                    argList.Add(tankFull.Value.ToString("0.00"));
                }
            }
            ManualCalcResult result = new ManualCalcResult();
			string typestr = "full";
			switch(datatype)
			{
				case 0: typestr = "weight";break;
				case 1: typestr = "density"; break;
				case 2: typestr = "inn"; break;
				case 3: typestr = "volume"; break;
			}
			string outputstr = "{Manual}#{" + string.Format("{0}", typestr) + "}#{";
            string resultStr = CallPipeCalc(outputstr + string.Join("#", argList) + "#}");
			if(resultStr == null || resultStr.Length == 0)
			{
				List<TankCalcState> tankCalcStates = new List<TankCalcState>();
				foreach(KeyValuePair<string, double> tankFull in tankFullDic)
				{
					TankCalcState tankState = new TankCalcState();
					tankState.Abname = tankFull.Key;
					tankState.Inn = tankFull.Value;
					tankCalcStates.Add(tankState);
				}
				result.tankCalcStates = tankCalcStates;
			}
			else
			{
				//string resultStr = CallPipeCalc("{Manual}#{full}#" + string.Join("#", argList) + "#}");
				int idx1 = resultStr.IndexOf("}#{");
				int idx2 = resultStr.LastIndexOf("}#{");
				if (idx1 >= 0 && idx2 >= 0 && idx1 != idx2)
				{
					string tankStr = resultStr.Substring(idx1 + 3, idx2 - idx1 - 3);

					string shipStr = resultStr.Substring(idx2 + 3);
					string[] tankParts = tankStr.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
					for (int i = 0; i < tankParts.Length; i += 12)
					{
						TankCalcState tankState = new TankCalcState();
						tankState.Weight = double.Parse(tankParts[i + 1]);
						tankState.Density = double.Parse(tankParts[i + 2]);
						tankState.Inn = double.Parse(tankParts[i + 3]);
						tankState.Volume = double.Parse(tankParts[i + 4]);
						tankState.Full = double.Parse(tankParts[i + 5]) * 100;
						tankState.LCG = double.Parse(tankParts[i + 6]);
						tankState.TCG = double.Parse(tankParts[i + 7]);
						tankState.VCG = double.Parse(tankParts[i + 8]);
						tankState.Start = double.Parse(tankParts[i + 9]);
						tankState.End = double.Parse(tankParts[i + 10]);
						tankState.Rate = double.Parse(tankParts[i + 11]);
						if (tankName2IdDic.ContainsKey(tankParts[i]))
						{
							string tankId = tankName2IdDic[tankParts[i]];
							result.SetTankCalcStateById(tankState, tankId);
						}
					}

					string[] shipParts = shipStr.Replace("{", "").Replace("}", "")
						.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
					if (shipParts.Length == 12)
					{
						result.ShipCalc.Disp = double.Parse(shipParts[0]);
						result.ShipCalc.Cargow = double.Parse(shipParts[1]);
						result.ShipCalc.Ballastw = double.Parse(shipParts[2]);
						result.ShipCalc.KMT = double.Parse(shipParts[3]);
						result.ShipCalc.LCG = double.Parse(shipParts[4]);
						result.ShipCalc.VCG = double.Parse(shipParts[5]);
						result.ShipCalc.GM = double.Parse(shipParts[6]);
						result.ShipCalc.TM = double.Parse(shipParts[7]);
						result.ShipCalc.Heel = double.Parse(shipParts[8]);
						result.ShipCalc.Trim = double.Parse(shipParts[9]);
						result.ShipCalc.MaxPersf = double.Parse(shipParts[10]);
						result.ShipCalc.MaxPerbm = double.Parse(shipParts[11]);
					}
				}
			}
			return result;
		}

		//用于自动生成后续的装卸步骤
		public ManualCalcResult CallAutoCalc(Dictionary<string, double> tankFullDic, int datatype)
		{
			List<string> argList = new List<string>();
			foreach (KeyValuePair<string, double> tankFull in tankFullDic)
			{
				if (tankId2NameDic.ContainsKey(tankFull.Key))
				{
					argList.Add(tankId2NameDic[tankFull.Key]);
					argList.Add(tankFull.Value.ToString("0.00"));
				}
			}
			ManualCalcResult result = new ManualCalcResult();
			string typestr = "full";
			switch (datatype)
			{
				case 0: typestr = "weight"; break;
				case 1: typestr = "density"; break;
				case 2: typestr = "inn"; break;
				case 3: typestr = "volume"; break;
			}
			string outputstr = "{AutoSeq}#{" + string.Format("{0}", typestr) + "}#{";
			string resultStr = CallPipeCalc(outputstr + string.Join("#", argList) + "#}");
			//string resultStr = CallPipeCalc("{Manual}#{full}#" + string.Join("#", argList) + "#}");
			if(resultStr == null)
				return null;
			int idx1 = resultStr.IndexOf("}#{");
			int idx2 = resultStr.LastIndexOf("}#{");
			if (idx1 >= 0 && idx2 >= 0 && idx1 != idx2)
			{
				string tankStr = resultStr.Substring(idx1 + 3, idx2 - idx1 - 3);

				string shipStr = resultStr.Substring(idx2 + 3);
				string[] tankParts = tankStr.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i + 12 <= tankParts.Length; i += 12)
				{
					TankCalcState tankState = new TankCalcState();
					tankState.Weight = double.Parse(tankParts[i + 1]);
					tankState.Density = double.Parse(tankParts[i + 2]);
					tankState.Inn = double.Parse(tankParts[i + 3]);
					tankState.Volume = double.Parse(tankParts[i + 4]);
					tankState.Full = double.Parse(tankParts[i + 5]) * 100;
					tankState.LCG = double.Parse(tankParts[i + 6]);
					tankState.TCG = double.Parse(tankParts[i + 7]);
					tankState.VCG = double.Parse(tankParts[i + 8]);
					tankState.Start = double.Parse(tankParts[i + 9]);
					tankState.End = double.Parse(tankParts[i + 10]);
					tankState.Rate = double.Parse(tankParts[i + 11]);
					if (tankName2IdDic.ContainsKey(tankParts[i]))
					{
						string tankId = tankName2IdDic[tankParts[i]];
						result.SetTankCalcStateById(tankState, tankId);
					}
				}

				string[] shipParts = shipStr.Replace("{", "").Replace("}", "")
					.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
				if (shipParts.Length == 12)
				{
					result.ShipCalc.Disp = double.Parse(shipParts[0]);
					result.ShipCalc.Cargow = double.Parse(shipParts[1]);
					result.ShipCalc.Ballastw = double.Parse(shipParts[2]);
					result.ShipCalc.KMT = double.Parse(shipParts[3]);
					result.ShipCalc.LCG = double.Parse(shipParts[4]);
					result.ShipCalc.VCG = double.Parse(shipParts[5]);
					result.ShipCalc.GM = double.Parse(shipParts[6]);
					result.ShipCalc.TM = double.Parse(shipParts[7]);
					result.ShipCalc.Heel = double.Parse(shipParts[8]);
					result.ShipCalc.Trim = double.Parse(shipParts[9]);
					result.ShipCalc.MaxPersf = double.Parse(shipParts[10]);
					result.ShipCalc.MaxPerbm = double.Parse(shipParts[11]);
				}

				return result;
			}

			return null;
		}

        //待测试，临时函数用于模拟演示
        public ManualCalcResult CallManualCalcA(Dictionary<string, double> tankFullDic, int time)
        {
            List<string> argList = new List<string>();
            foreach (KeyValuePair<string, double> tankFull in tankFullDic)
            {
                if (tankId2NameDic.ContainsKey(tankFull.Key))
                {
                    argList.Add(tankId2NameDic[tankFull.Key]);
                    double val = time * 0.1;
                    argList.Add(val.ToString("0.00"));
                }
            }
            ManualCalcResult result = new ManualCalcResult();
            string typestr = "full";
            string outputstr = "{Manual}#{" + string.Format("{0}", typestr) + "}#{";
            string resultStr = CallPipeCalc(outputstr + string.Join("#", argList) + "#}");
            //string resultStr = CallPipeCalc("{Manual}#{full}#" + string.Join("#", argList) + "#}");
            int idx1 = resultStr.IndexOf("}#{");
            int idx2 = resultStr.LastIndexOf("}#{");
            if (idx1 >= 0 && idx2 >= 0 && idx1 != idx2)
            {
                string tankStr = resultStr.Substring(idx1 + 3, idx2 - idx1 - 3);

                string shipStr = resultStr.Substring(idx2 + 3);
                string[] tankParts = tankStr.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i + 12 <= tankParts.Length; i += 12)
                {
                    TankCalcState tankState = new TankCalcState();
                    tankState.Weight = double.Parse(tankParts[i + 1]);
                    tankState.Density = double.Parse(tankParts[i + 2]);
                    tankState.Inn = double.Parse(tankParts[i + 3]);
                    tankState.Volume = double.Parse(tankParts[i + 4]);
                    tankState.Full = double.Parse(tankParts[i + 5]) * 100;
                    tankState.LCG = double.Parse(tankParts[i + 6]);
                    tankState.TCG = double.Parse(tankParts[i + 7]);
                    tankState.VCG = double.Parse(tankParts[i + 8]);
                    tankState.Start = double.Parse(tankParts[i + 9]);
                    tankState.End = double.Parse(tankParts[i + 10]);
                    tankState.Rate = double.Parse(tankParts[i + 11]);
                    if (tankName2IdDic.ContainsKey(tankParts[i]))
                    {
                        string tankId = tankName2IdDic[tankParts[i]];
                        result.SetTankCalcStateById(tankState, tankId);
                    }
                }

                string[] shipParts = shipStr.Replace("{", "").Replace("}", "")
                    .Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (shipParts.Length == 12)
                {
                    result.ShipCalc.Disp = double.Parse(shipParts[0]);
                    result.ShipCalc.Cargow = double.Parse(shipParts[1]);
                    result.ShipCalc.Ballastw = double.Parse(shipParts[2]);
                    result.ShipCalc.KMT = double.Parse(shipParts[3]);
                    result.ShipCalc.LCG = double.Parse(shipParts[4]);
                    result.ShipCalc.VCG = double.Parse(shipParts[5]);
                    result.ShipCalc.GM = double.Parse(shipParts[6]);
                    result.ShipCalc.TM = double.Parse(shipParts[7]);
                    result.ShipCalc.Heel = double.Parse(shipParts[8]);
                    result.ShipCalc.Trim = double.Parse(shipParts[9]);
                    result.ShipCalc.MaxPersf = double.Parse(shipParts[10]);
                    result.ShipCalc.MaxPerbm = double.Parse(shipParts[11]);
                }

                return result;
            }

            return null;
        }

        public ManualCalcResult CallPipeSingleCalc(string inputstr,string TankId)
        {
            ManualCalcResult result = new ManualCalcResult();
            string resultStr = CallPipeCalc(inputstr);
            int idx1 = resultStr.IndexOf("}#{");
            int idx2 = resultStr.LastIndexOf("}#{");
            if (idx1 >= 0 && idx2 >= 0 && idx1 != idx2)
            {
                string tankStr = resultStr.Substring(idx1 + 3, idx2 - idx1 - 3);
                string shipStr = resultStr.Substring(idx2 + 3);
                string[] tankParts = tankStr.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i + 12 <= tankParts.Length; i += 12)
				{
					TankCalcState tankState = new TankCalcState();
					tankState.Weight = double.Parse(tankParts[i + 1]);
					tankState.Density = double.Parse(tankParts[i + 2]);
					tankState.Inn = double.Parse(tankParts[i + 3]);
					tankState.Volume = double.Parse(tankParts[i + 4]);
					tankState.Full = double.Parse(tankParts[i + 5]) * 100;
					tankState.LCG = double.Parse(tankParts[i + 6]);
					tankState.TCG = double.Parse(tankParts[i + 7]);
					tankState.VCG = double.Parse(tankParts[i + 8]);
					tankState.Start = double.Parse(tankParts[i + 9]);
					tankState.End = double.Parse(tankParts[i + 10]);
					tankState.Rate = double.Parse(tankParts[i + 11]);
					if (tankName2IdDic.ContainsKey(tankParts[i]))
					{
						string tankId = tankName2IdDic[tankParts[i]];
						result.SetTankCalcStateById(tankState, tankId);
					}
				}

                string[] shipParts = shipStr.Replace("{", "").Replace("}", "")
                   .Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (shipParts.Length == 12)
                {
                    result.ShipCalc.Disp = double.Parse(shipParts[0]);
                    result.ShipCalc.Cargow = double.Parse(shipParts[1]);
                    result.ShipCalc.Ballastw = double.Parse(shipParts[2]);
                    result.ShipCalc.KMT = double.Parse(shipParts[3]);
                    result.ShipCalc.LCG = double.Parse(shipParts[4]);
                    result.ShipCalc.VCG = double.Parse(shipParts[5]);
                    result.ShipCalc.GM = double.Parse(shipParts[6]);
                    result.ShipCalc.TM = double.Parse(shipParts[7]);
                    result.ShipCalc.Heel = double.Parse(shipParts[8]);
                    result.ShipCalc.Trim = double.Parse(shipParts[9]);
                    result.ShipCalc.MaxPersf = double.Parse(shipParts[10]);
                    result.ShipCalc.MaxPerbm = double.Parse(shipParts[11]);
                }
                return result;
            }
            return null;
        }


        public ManualCalcResult CallAutoSeqCalc(Dictionary<string, double> tankFullDic)
        {
            List<string> argList = new List<string>();
            foreach(KeyValuePair<string, double> tankFull in tankFullDic)
            {
                if (tankId2NameDic.ContainsKey(tankFull.Key))
                {
                    argList.Add(tankId2NameDic[tankFull.Key]);
                    argList.Add(tankFull.Value.ToString("0.00"));
                }
            }

            string resultStr = CallPipeCalc("{AutoSeq}#{full}#" + string.Join("#", argList) + "#}");
            int idx1 = resultStr.IndexOf("}#{");
            int idx2 = resultStr.LastIndexOf("}#{");
            if (idx1 >= 0 && idx2 >= 0 && idx1 != idx2)
            {
                ManualCalcResult result = new ManualCalcResult();
                string tankStr = resultStr.Substring(idx1 + 3, idx2 - idx1 - 3);
                string shipStr = resultStr.Substring(idx2 + 3);
                string[] tankParts = tankStr.Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i + 11 < tankParts.Length; i += 11)
                {
                    TankCalcState tankState = new TankCalcState();
                    tankState.Weight = double.Parse(tankParts[i + 1]);
                    tankState.Density = double.Parse(tankParts[i + 2]);
                    tankState.Inn = double.Parse(tankParts[i + 3]);
                    tankState.Volume = double.Parse(tankParts[i + 4]);
                    tankState.Full = double.Parse(tankParts[i + 5]);
                    tankState.LCG = double.Parse(tankParts[i + 6]);
                    tankState.TCG = double.Parse(tankParts[i + 7]);
                    tankState.VCG = double.Parse(tankParts[i + 8]);
                    tankState.Start = double.Parse(tankParts[i + 9]);
                    tankState.End = double.Parse(tankParts[i + 10]);
                    if (tankName2IdDic.ContainsKey(tankParts[i]))
                    {
                        string tankId = tankName2IdDic[tankParts[i]];
						result.SetTankCalcState(tankState);
                    }
                }

                string[] shipParts = shipStr.Replace("{", "").Replace("}", "")
                    .Split("#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (shipParts.Length == 12)
                {
                    result.ShipCalc.Disp = double.Parse(shipParts[0]);
                    result.ShipCalc.Cargow = double.Parse(shipParts[1]);
                    result.ShipCalc.Ballastw = double.Parse(shipParts[2]);
                    result.ShipCalc.KMT = double.Parse(shipParts[3]);
                    result.ShipCalc.LCG = double.Parse(shipParts[4]);
                    result.ShipCalc.VCG = double.Parse(shipParts[5]);
                    result.ShipCalc.GM = double.Parse(shipParts[6]);
                    result.ShipCalc.TM = double.Parse(shipParts[7]);
                    result.ShipCalc.Heel = double.Parse(shipParts[8]);
                    result.ShipCalc.Trim = double.Parse(shipParts[9]);
                    result.ShipCalc.MaxPersf = double.Parse(shipParts[10]);
                    result.ShipCalc.MaxPerbm = double.Parse(shipParts[11]);
                }

                return result;
            }
            return null;
        }
        private string CallPipeCalc(string tankState)
        {
            lock (this)
            {
                try
                {
                    if (pipeClient == null)
                    {
                        pipeClient = new NamedPipeClientStream("localhost", "mynamedpipe", PipeDirection.InOut, PipeOptions.None,
                            System.Security.Principal.TokenImpersonationLevel.None);
                        pipeClient.Connect(1000);
                        pipeReader = new StreamReader(pipeClient);
                        pipeWriter = new StreamWriter(pipeClient);
                    }

                    pipeWriter.WriteLine(tankState);
                    pipeWriter.Flush();
                    return pipeReader.ReadLine();
                }
                catch (Exception ex)
                {
                    try
                    {
                        if (pipeWriter != null)
                        {
                            pipeWriter.Close();
                        }
                        if (pipeReader != null)
                        {
                            pipeReader.Close();
                        }
                        if (pipeClient != null)
                        {
                            pipeClient.Close();
                        }
                    }
                    finally
                    {
                        pipeWriter = null;
                        pipeReader = null;
                        pipeClient = null;
                    }
                }
            }

            return string.Empty;
        }


        public void Dispose()
        {
            try
            {
                if (pipeClient != null)
                {
                    pipeClient.Close();
                }
                if (pipeWriter != null)
                {
                    pipeWriter.Close();
                }
                if (pipeReader != null)
                {
                    pipeReader.Close();
                }
            }
            catch
            { 
            }
        }
    }
}
